﻿#include "page_router.h"
#include <QDebug>
#include <QElapsedTimer>
#include <qevent.h>
#include <QTimer>

namespace flow
{
void PageRouter::push(QWidget* widget, int pos) const
{
    Q_ASSERT(_view);
    Q_ASSERT(widget);
    // 如果已经存在当前对象
    bool exists = false;
    for (int i = 0; i < _view->count(); ++i) {
        if (_view->widget(i) == widget) {
            exists = true;
        }
    }
    if (!exists) {
        if (pos >= 0) {
            _view->insertWidget(pos, widget);
        }
        else {
            _view->addWidget(widget);
        }
    }
    _view->setCurrentWidget(widget);
}

QSharedPointer<PageRouter::Future> PageRouter::push(QString route, PayloadType args)
{
    for (const auto& pushNamedInterceptor : _pushNamedInterceptors) {
        if (!pushNamedInterceptor(route, args)) {
            return {};
        }
    }
    if (!_view) {
        _view = _viewContainer->findChild<RouterView*>(QString(), Qt::FindDirectChildrenOnly);
        if (!_view) {
            return {};
        }
    }
    const QString fromRoute = _view->currentWidget() ? _view->currentWidget()->property("route").toString() : "";
    if (_redirectMap.contains(route)) {
        route = _redirectMap.value(route);
    }
    if (!contains(route)) {
        if (contains("/404")) {
            return push("/404", {{"route", route}});
        }
        throw std::logic_error(QString("route path %1 not found!").arg(route).toStdString());
    }

    // 如果页面中已经存在当前路径, 直接显示
    for (int i = 0; i < _view->count(); ++i) {
        auto* w = _view->widget(i);
        if (w->property("route").toString() == route) {
            _view->setCurrentWidget(w);
            emit routeChanged(fromRoute, route);
            return _routePopValue[viewId()][route];
        }
    }
    // 否则根据路由创建一个
    const auto& widget = dispatch(route, args);
    widget->setProperty("route", route);

    // before
    push(widget);
    _routePopValue[viewId()][route].reset(new Future);
    _routesView[viewId()][route] = widget;
    connect(widget, &QWidget::destroyed, [this](QObject* obj) {
        if (obj) {
            _routesView[viewId()].remove(obj->property("route").toString());
        }
    });
    // after
    emit routeChanged(fromRoute, route);

    return _routePopValue[viewId()][route];
}

bool PageRouter::findParentRouterView()
{
    if (!_viewContainer) {
        return false;
    }
    while (_viewContainer) {
        const auto& parentWidget = _viewContainer->parentWidget();
        if (!parentWidget) {
            return false;
        }
        if (_view = dynamic_cast<RouterView*>(parentWidget); _view == nullptr) {
            _viewContainer = parentWidget;
        }
        else {
            break;
        }
    }
    return !!_view;
}

void PageRouter::popNamed(const QString& route, const PopParams& arguments)
{
    for (int i = 0; i < _view->count(); ++i) {
        if (const auto widget = _view->widget(i); widget->property("route").toString() == route) {
            _view->removeWidget(widget);
            widget->deleteLater();
            afterPop(route, arguments);
            return;
        }
    }
}

void PageRouter::popCurrent(const PageRouter::PopParams& arguments, QString& route)
{
    const int index = _view->currentIndex() - 1;
    route           = _view->currentWidget()->property("route").toString();
    if (arguments.keepAlive) {
        _view->setCurrentIndex(index);
    }
    else {
        if (const auto currentWidget = _view->currentWidget()) {
            _view->removeWidget(currentWidget);
            currentWidget->deleteLater();
            // delete currentWidget;
        }
    }
    afterPop(route, arguments);
    // 走一次 push
    // if (const auto w = _view->currentWidget()) {
    //    if (!push(w->property("route").toString())) {
    //        // throw std::logic_error("push error");
    //        push("/blank");
    //    }
    //}
}

void PageRouter::pop(PopParams arguments)
{
    if (!_view) {
        if (!findParentRouterView()) {
            return;
        }
    }
    if (_view->count() == 0) {
        of(_view->parentWidget()).pop();
        return;
    }
    QString route = arguments.route;
    if (!route.isEmpty()) {
        // 查找指定页面
        return popNamed(route, arguments);
    }
    popCurrent(arguments, route);
    // QTimer::singleShot(10, [this, arguments] {});
}

void PageRouter::afterPop(const QString& route, const PopParams& arguments)
{
    auto& futures = _routePopValue[viewId()];
    if (futures.contains(route)) {
        if (futures[route]) {
            futures[route]->complete(arguments.value);
        }
        futures.remove(route);
    }
    if (futures.isEmpty()) {
        _routePopValue.remove(viewId());
    }
    auto& widgets = _routesView[viewId()];
    if (widgets.contains(route)) {
        if (widgets[route]) {
            widgets.remove(route);
        }
    }
    if (widgets.isEmpty()) {
        _routesView.remove(viewId());
    }
}

size_t PageRouter::viewId() const
{
    return qHash(_view);
}

QSharedPointer<PageRouter::Future> PageRouter::replace(const QString& route, PayloadType pushArgs, PopParams popArgs)
{
    // 如果页面中已经存在当前路径, 直接显示
    if (!_view) {
        _view = _viewContainer->findChild<RouterView*>(QString(), Qt::FindDirectChildrenOnly);
        if (!_view) {
            return {};
        }
    }
    if (const auto& widget = _view->currentWidget()) {
        const auto currentRoute = widget->property("route").toString();
        if (currentRoute == route) {
            return _routePopValue[viewId()][route];
        }
        // 移除之前的页面
        // 手动调用析构？
        afterPop(currentRoute, popArgs);
    }
    // 当前页面弹出并压入指定页面
    // 当前页面
    // 先显示指定页面，防止闪烁
    auto f = push(route, pushArgs);
    if (!_view) {
        return f;
    }
    if (_view->currentIndex() == 0) {
        return f;
    }
    // 移除之前的页面
    if (const auto currentWidget = _view->widget(_view->currentIndex() - 1)) {
        _view->removeWidget(currentWidget);
        currentWidget->deleteLater();
    }
    // afterPop(route, popArgs);
    return f;
}

void PageRouter::defineRedirect(const QString& from, const QString& to)
{
    _redirectMap[from] = to;
}

void PageRouter::removeRedirect(const QString& from)
{
    if (_redirectMap.contains(from)) {
        _redirectMap.remove(from);
    }
}

// void PageRouter::replace(QStringView path, PayloadType params) { }

PageRouter& PageRouter::of(QWidget* view)
{
    if (const auto v = dynamic_cast<RouterView*>(view)) {
        _view          = v;
        _viewContainer = _view->parentWidget();
    }
    else {
        _viewContainer = view;
        _view          = nullptr;
        //_view          = _viewContainer->findChild<RouterView*>(QString(), Qt::FindDirectChildrenOnly);
    }
    return *this;
}

PageRouter& PageRouter::of(const QString& route)
{
    _viewContainer = this->find(route);
    return of(_viewContainer);
}

QWidget* PageRouter::find(const QString& route) const
{
    auto widgets = _routesView[viewId()];
    if (widgets.contains(route)) {
        return widgets[route];
    }
    for (const auto& ws : _routesView) {
        if (ws.contains(route)) {
            return ws[route];
        }
    }
    return nullptr;
}

QWidget* PageRouter::currentWidget() const
{
    if (_view) {
        return _view->currentWidget();
    }
    return nullptr;
}

void PageRouter::addPushNamedInterceptor(const RequestInterceptor& interceptor)
{
    _pushNamedInterceptors.push_back(interceptor);
}

bool PageRouter::dynamicDefine(const QString& route, PayloadType args)
{
    // 替换原始路由中的参数为输入的参数值并添加路由，路由规则回调为原始路由回调。
    if (!contains(route)) {
        return false;
    }
    const auto builder = handler(route);
    QString newRoute   = route;
    for (const auto& key : args.keys()) {
        newRoute.replace(QString("{%1}").arg(key), args.value(key).toString());
    }
    define(newRoute, builder);
    return true;
}
} // namespace flow
